﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.IO.Ports;
using Modbus.Device;
using Modbus.Utility;
using System.Diagnostics;

namespace executeCommands
{
    
     
    class command 
    {
        public enum value_t { float_t, word_t }
        public enum RW { read, write }
        public enum regType { holding_t, input_t }

        private RW RWvalue;
        private value_t WordFloatValue;
        private regType registerType;
        
        private int address;
        private UInt16 data_w;
        private float data_f;
        private string origCommand;
        private string returnCode;
        
        
        static public SerialPort port;
        static public int modbusId;

   
        public command(value_t valueType, RW readWriteValue, regType inregisterType, int inAddress, string indata)
        {
            WordFloatValue = valueType;
            RWvalue = readWriteValue;
            registerType = inregisterType;
            address = inAddress;
            if (readWriteValue == RW.write)
            {
                if (valueType == value_t.float_t)
                {
                    data_f = float.Parse(indata);
                }
                else if (valueType == value_t.word_t)
                {
                    data_w = UInt16.Parse(indata);
                }
            }

        }

        public long DoReadorWrite()
        {
            using (port)
            {
                // configure serial port
                port.DataBits = 8;
                port.Parity = Parity.None;
                port.StopBits = StopBits.One;

                try
                {
                    port.Open();
                }
                catch (Exception err)
                {
                    throw err;
                }

                // create modbus master
                IModbusSerialMaster master = ModbusSerialMaster.CreateRtu(port);

                byte slaveID = (byte) modbusId;
                master.Transport.ReadTimeout = 50;
                
                // actually execute command
                
                long timeTaken=0;
                returnCode = null;
                try
                {
                    timeTaken = preformCommunication(master, slaveID);
                }
                catch (Exception err)
                {
                    throw err;
                    //returnCode = err.Message;    
                }

                if (returnCode == null)
                {
                    returnCode = "Ok";
                }

                return timeTaken;
            }
        }

        private long preformCommunication(IModbusSerialMaster master, byte slaveID)
        {
            Stopwatch timer = new Stopwatch();
            timer.Reset();
            timer.Start();
            //if input registers
            if (registerType == regType.input_t)
            {
                handleInputRegisterRead(master, slaveID);
                timer.Stop();
                return timer.ElapsedMilliseconds;
            }

            //if holding registers
            if (RWvalue == RW.read)
            {
                handleHoldingRegisterRead(master, slaveID);
            }

            if (RWvalue == RW.write)
            {
                HandleHoldingRegisterWrite(master, slaveID);
            }


            timer.Stop();
            return timer.ElapsedMilliseconds;
        }

        private void HandleHoldingRegisterWrite(IModbusSerialMaster master, byte slaveID)
        {
            if (WordFloatValue == value_t.word_t)
            {
                master.WriteSingleRegister(slaveID, (ushort)(address  - 1), data_w);
            }
            else
            {
                byte[] all = BitConverter.GetBytes(data_f);
                ushort[] array = new ushort[2];
                array[1] = BitConverter.ToUInt16(all, 0);
                array[0] = BitConverter.ToUInt16(all, 2);

                master.WriteMultipleRegisters(slaveID, (ushort)(address  - 1), array);
            }
        }

        private void handleHoldingRegisterRead(IModbusSerialMaster master, byte slaveID)
        {
            if (WordFloatValue == value_t.word_t)
            {
                ushort[] input = master.ReadHoldingRegisters(slaveID, (ushort)(address  - 1), 1);
                data_w = input[0];
            }
            else
            {
                ushort[] input = master.ReadHoldingRegisters(slaveID, (ushort)(address  - 1), 2);
                data_f = ModbusUtility.GetSingle(input[0], input[1]);
            }
        }

        private void handleInputRegisterRead(IModbusSerialMaster master, byte slaveID)
        {
            if (WordFloatValue == value_t.word_t)
            {
                ushort[] input = master.ReadHoldingRegisters(slaveID, (ushort)(address  - 1), 1);
                data_w = input[0];
            }
            else
            {
                ushort[] input = master.ReadHoldingRegisters(slaveID, (ushort)(address  - 1), 2);
                data_f = ModbusUtility.GetSingle(input[0], input[1]);
            }
        }

        public string result
        {
            get
            {
                if (WordFloatValue == value_t.word_t)
                {
                    return data_w.ToString();
                }

                if (WordFloatValue == value_t.float_t)
                {
                    return data_f.ToString();
                }

                return "";
            }
        }
    }
    
    
    
    
}
